package com.etc.aspect;

import java.lang.reflect.Method;
import java.sql.Timestamp;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.etc.common.enums.StatusEnum;
import com.etc.common.exception.SysOperationException;
import com.etc.common.util.DateUtils;
import com.etc.constants.ModuleConstants;
import com.etc.constants.WebConstants;
import com.etc.logManage.service.ILogOperationService;
import com.etc.logManage.vo.LogOperationVO;
import com.etc.user.model.User;

/**
 * @description 切面类，拦截controller和service自定义注解的方法
 * @author 黄宇 E-mail: yuanddan2006@126.com
 * @date 创建时间：2016年3月23日 下午3:02:56
 * @version 1.0
 */
@Aspect
@Component
public class LogOperationAspect {

	Logger log = LoggerFactory.getLogger(LogOperationAspect.class);

	@Autowired
	ILogOperationService logOperationService;

	/**
	 * Controller层切点
	 */
	@Pointcut("@annotation(com.etc.annotation.LogOperation)")
	public void controllerAspect() {
	}

	/**
	 * controller切面前置通知
	 * 
	 * @param joinPoint
	 */
	@Before("controllerAspect()")
	public void beforeMethod(JoinPoint joinPoint) {
		this.saveLogOperation(joinPoint, StatusEnum.SUCCESS);
	}

	/**
	 * controller异常切面通知
	 * 
	 * @param joinPoint
	 */
	@AfterThrowing("controllerAspect()")
	public void afterThrow(JoinPoint joinPoint) {
		this.saveLogOperation(joinPoint, StatusEnum.FAIL);
	}

	/**
	 * @param joinPoint
	 * @param operationStatus
	 */
	private void saveLogOperation(JoinPoint joinPoint, StatusEnum operationStatus) {
		try {
			// 获取当前用户
			HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
					.getRequestAttributes()).getRequest();
			HttpSession session = request.getSession();
			User user = (User) session.getAttribute(WebConstants.USER_KEY);
			LogOperationVO vo = new LogOperationVO();
			// 获取模块信息
			String moduleName = this.getModuleName(joinPoint);
			// 获取功能信息
			String operationName = this.getOperationName(joinPoint);
			// 获取操作url
			String url = this.getOperationUrl(joinPoint);
			// 详细信息
			String contont = ModuleConstants.MODULE_MAP.get(moduleName)
					+ ModuleConstants.OPERATION_MAP.get(operationName);

			vo.setTloUrl(url);
			vo.setTsuName(user.getTsuName());
			vo.setTsmName(moduleName);
			vo.setTsoName(operationName);
			vo.setTloContent(contont);
			vo.setTloTime(DateUtils.getCurrentDate());
			logOperationService.insert(vo);
		} catch (SysOperationException e) {
			log.error(e.getMessage(), e);
		} catch (Exception e) {
			log.error("记录用户操作日志异常!", e);
		}
	}

	/**
	 * 获取操作功能名称
	 * 
	 * @param joinPoint
	 * @return
	 */
	private String getOperationName(JoinPoint joinPoint) {
		// 当前请求类的名称
		String targetName = joinPoint.getTarget().getClass().getName();
		// 当前请求方法的名称
		String methodName = joinPoint.getSignature().getName();
		try {
			Class<?> targetClass = Class.forName(targetName);
			Method[] methods = targetClass.getMethods();

			// 找到当前请求的方法
			for (Method method : methods) {

				if (method.getName().equals(methodName)) {
					// 找到RequestMapping注解
					if (method.isAnnotationPresent(RequestMapping.class)) {
						RequestMapping mapping = method.getAnnotation(RequestMapping.class);
						return mapping.method()[0].toString();
					}
				}
			}

		} catch (Exception e) {
			throw new SysOperationException("记录日志时，获取功能名称失败", e);
		}
		return null;
	}

	/**
	 * 通过获取请求controller的类名类获取模块名称
	 * 
	 * @param joinPoint
	 * @return
	 */
	private String getModuleName(JoinPoint joinPoint) {
		// 当前请求类的名称
		String targetName = joinPoint.getTarget().getClass().getSimpleName();
		if (targetName.lastIndexOf("Controller") >= 0) {
			return targetName.replace("Controller", "");
		} else {
			throw new SysOperationException("记录操作日志时，获取模块信息异常!");
		}

	}

	/**
	 * 通过请求的controller的@RequestMapping和对应方法的@RequestMapping注解，来取到请求的url
	 * 
	 * @param joinPoint
	 * @return
	 * @throws Exception
	 */
	private String getOperationUrl(JoinPoint joinPoint) {
		// 当前请求类的名称
		String targetName = joinPoint.getTarget().getClass().getName();
		// 当前请求方法的名称
		String methodName = joinPoint.getSignature().getName();
		try {
			Class<?> targetClass = Class.forName(targetName);
			Method[] methods = targetClass.getMethods();

			String operationUrl = "";

			// 找到当前类的@RequestMapping
			if (targetClass.isAnnotationPresent(RequestMapping.class)) {
				RequestMapping mapping = (RequestMapping) targetClass
						.getAnnotation(RequestMapping.class);
				operationUrl += mapping.value()[0];
			}

			// 找到当前请求的方法
			for (Method method : methods) {

				if (method.getName().equals(methodName)) {
					// 找到RequestMapping注解
					if (method.isAnnotationPresent(RequestMapping.class)) {
						RequestMapping mapping = method.getAnnotation(RequestMapping.class);
						operationUrl += mapping.value()[0];
						return operationUrl;
					}

				}
			}
		} catch (Exception e) {
			throw new SysOperationException("记录日志时，获取url失败", e);
		}
		return null;
	}

	public static void main(String[] args) {
		System.out.println(StatusEnum.FAIL.getIndex());
	}

}
